package com.whmskj.xjlhsc.qianYiData.service.impl;

import com.whmskj.xjlhsc.qianYiData.dto.ProcessRunStatsChange;
import com.whmskj.xjlhsc.qianYiData.dto.ProcessRunStatsRow;
import com.whmskj.xjlhsc.qianYiData.dto.ProcessRunStatsSyncResult;
import com.whmskj.xjlhsc.qianYiData.mapper.ProcessRunStatsMapper;
import com.whmskj.xjlhsc.qianYiData.service.ProcessRunStatsService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.*;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ProcessRunStatsServiceImpl implements ProcessRunStatsService {

    private static final ZoneId ZONE = ZoneId.of("Asia/Shanghai");

    private static class ShiftWindow {
        final LocalDateTime start;
        final LocalDateTime end;
        final LocalDateTime now;
        ShiftWindow(LocalDateTime start, LocalDateTime end, LocalDateTime now) {
            this.start = start; this.end = end; this.now = now;
        }
    }

    @Resource
    private ProcessRunStatsMapper mapper;

    @Override
    public int sync() {
        int updated = mapper.updateStats();
        int inserted = mapper.insertMissingStats();

        // 覆盖为实时班次口径的运转率
        ShiftWindow win = currentShiftWindow();
        mapper.updateRunRateByShift(Date.from(win.start.atZone(ZONE).toInstant()),
                                    Date.from(win.end.atZone(ZONE).toInstant()),
                                    Date.from(win.now.atZone(ZONE).toInstant()));
        return updated + inserted;
    }

    @Override
    public ProcessRunStatsSyncResult syncWithLogs() {
        // 1) 读取当前表中的旧值
        List<ProcessRunStatsRow> currentList = Optional.ofNullable(mapper.selectCurrentStats()).orElse(Collections.emptyList());
        Map<String, ProcessRunStatsRow> current = currentList.stream()
                .filter(r -> r.getProcess() != null)
                .collect(Collectors.toMap(r -> r.getProcess().trim(), Function.identity(), (a,b)->a));

        // 2) 计算最新的计数类（开停台/品种）以及基于班次口径的运转率（未写入表）
        List<ProcessRunStatsRow> computedList = Optional.ofNullable(mapper.selectComputedStats()).orElse(Collections.emptyList());
        Map<String, ProcessRunStatsRow> computed = computedList.stream()
                .filter(r -> r.getProcess() != null)
                .collect(Collectors.toMap(r -> r.getProcess().trim(), Function.identity(), (a,b)->a));

        ShiftWindow win = currentShiftWindow();
        List<ProcessRunStatsRow> shiftRates = Optional.ofNullable(
                mapper.selectRunRateByShift(
                        Date.from(win.start.atZone(ZONE).toInstant()),
                        Date.from(win.end.atZone(ZONE).toInstant()),
                        Date.from(win.now.atZone(ZONE).toInstant())
                )
        ).orElse(Collections.emptyList());
        Map<String, ProcessRunStatsRow> rateMap = shiftRates.stream()
                .filter(r -> r.getProcess() != null)
                .collect(Collectors.toMap(r -> r.getProcess().trim(), Function.identity(), (a,b)->a));

        // 3) 形成差异（仅记录会发生变化或新增的工序）
        Set<String> allKeys = new HashSet<>();
        allKeys.addAll(current.keySet());
        allKeys.addAll(computed.keySet());
        allKeys.addAll(rateMap.keySet());

        List<ProcessRunStatsChange> changes = new ArrayList<>();
        for (String key : allKeys) {
            ProcessRunStatsRow before = current.get(key);
            ProcessRunStatsRow computedAfter = computed.get(key); // counts + openingRate (开台率)
            ProcessRunStatsRow rateAfter = rateMap.get(key);      // runRate (运转率)
            if (computedAfter == null && rateAfter == null) {
                // 没有任何计算结果
                continue;
            }
            boolean isInsert = (before == null);
            Integer afterOpenings = computedAfter == null ? null : computedAfter.getNumberOfOpenings();
            Integer afterStoppings = computedAfter == null ? null : computedAfter.getStoppings();
            Integer afterSpecies = computedAfter == null ? null : computedAfter.getNumberOfSpecies();
            Integer afterSafeguards = computedAfter == null ? null : computedAfter.getNumberOfSafeguardsPending();
            java.math.BigDecimal afterOpeningRate = computedAfter == null ? null : computedAfter.getOpeningRate();
            java.math.BigDecimal afterRunRate = rateAfter == null ? null : rateAfter.getRunRate();

            boolean diff = isInsert
                    || notEquals(before.getNumberOfOpenings(), afterOpenings)
                    || notEquals(before.getStoppings(), afterStoppings)
                    || notEquals(before.getNumberOfSpecies(), afterSpecies)
                    || notEquals(before.getNumberOfSafeguardsPending(), afterSafeguards)
                    || notEquals(before.getOpeningRate(), afterOpeningRate)
                    || notEquals(before.getRunRate(), afterRunRate);
            if (diff) {
                ProcessRunStatsChange c = new ProcessRunStatsChange();
                c.setProcess(key);
                if (before != null) {
                    c.setBeforeNumberOfOpenings(before.getNumberOfOpenings());
                    c.setBeforeStoppings(before.getStoppings());
                    c.setBeforeNumberOfSpecies(before.getNumberOfSpecies());
                    c.setBeforeNumberOfSafeguardsPending(before.getNumberOfSafeguardsPending());
                    c.setBeforeOpeningRate(before.getOpeningRate());
                    c.setBeforeRunRate(before.getRunRate());
                }
                c.setAfterNumberOfOpenings(afterOpenings);
                c.setAfterStoppings(afterStoppings);
                c.setAfterNumberOfSpecies(afterSpecies);
                c.setAfterNumberOfSafeguardsPending(afterSafeguards);
                c.setAfterOpeningRate(afterOpeningRate);
                c.setAfterRunRate(afterRunRate);
                changes.add(c);
            }
        }

        // 4) 实际写入数据库：先更新计数，再更新班次口径运转率
        int updated = mapper.updateStats();
        int inserted = mapper.insertMissingStats();
        mapper.updateRunRateByShift(
                Date.from(win.start.atZone(ZONE).toInstant()),
                Date.from(win.end.atZone(ZONE).toInstant()),
                Date.from(win.now.atZone(ZONE).toInstant())
        );

        // 5) 返回结果
        ProcessRunStatsSyncResult result = new ProcessRunStatsSyncResult();
        result.setUpdated(updated);
        result.setInserted(inserted);
        result.getChanges().addAll(changes);
        return result;
    }

    private ShiftWindow currentShiftWindow() {
        LocalDateTime now = LocalDateTime.now(ZONE);
        LocalDate today = now.toLocalDate();
        LocalTime t0930 = LocalTime.of(9, 30);
        LocalTime t2130 = LocalTime.of(21, 30);
        LocalDateTime start;
        LocalDateTime end;
        if (!now.toLocalTime().isBefore(t0930) && now.toLocalTime().isBefore(t2130)) {
            // 早班：今天 09:30 ~ 今天 21:30
            start = LocalDateTime.of(today, t0930);
            end = LocalDateTime.of(today, t2130);
        } else if (!now.toLocalTime().isBefore(t2130)) {
            // 晚班：今天 21:30 ~ 明天 09:30
            start = LocalDateTime.of(today, t2130);
            end = LocalDateTime.of(today.plusDays(1), t0930);
        } else {
            // 凌晨：属于昨晚班 昨天 21:30 ~ 今天 09:30
            start = LocalDateTime.of(today.minusDays(1), t2130);
            end = LocalDateTime.of(today, t0930);
        }
        return new ShiftWindow(start, end, now);
    }

    private static boolean notEquals(Object a, Object b) {
        if (a == b) return false;
        if (a == null || b == null) return true;
        return !a.equals(b);
    }
}

